
module CsvTable where

import Table
import System.IO
import qualified Data.ByteString.Lazy.Char8 as L
import qualified Data.ByteString as BS
import Data.ByteString.Lex.Double

data CsvTable = CsvTable {
	csvColumns :: [Column],
	csvFileName :: String
}

lazyLines :: String -> IO [L.ByteString]
lazyLines fileName = do
	h <- openFile fileName ReadMode
	L.hGetContents h >>= (return . L.split '\n')

parseRow :: CsvTable -> L.ByteString -> Row
parseRow csvTable line = 
	let 
		fields = L.split ',' line
		cols = csvColumns csvTable
	in 
		Row [parseValue v c | (v,c) <- zip fields cols] 

showValue :: Maybe Value -> String
showValue value =
	case value of
		Nothing -> ""
		Just v -> show v

showRow :: Row -> String
showRow (Row (v:vs)) =
	(showValue v) ++ "," ++ (showRow $ Row vs)
showRow (Row []) = ""

parseValue :: L.ByteString -> Column -> Maybe Value
parseValue field ByteColumn =
	case L.readInt field of
		Nothing -> Nothing
		Just (k,rest) -> Just $ ByteValue $ fromIntegral k

parseValue field ShortColumn =
	case L.readInt field of
		Nothing -> Nothing
		Just (k,rest) -> Just $ ShortValue $ fromIntegral k

parseValue field IntColumn = 
	case L.readInteger field of
		Nothing -> Nothing
		Just (k,rest) -> Just $ IntValue $ fromIntegral k

parseValue field LongColumn = 
	case L.readInteger field of
		Nothing -> Nothing
		Just (k,rest) -> Just $ LongValue $ fromIntegral k

parseValue field FloatColumn =
	case readDouble $ BS.concat $ L.toChunks field of
		Nothing -> Nothing
		Just (k,rest) -> Just $ FloatValue $ realToFrac k

parseValue field DoubleColumn =
	case readDouble $ BS.concat $ L.toChunks field of
		Nothing -> Nothing
		Just (k,rest) -> Just $ DoubleValue k

instance Table CsvTable where
	
	columns csvTable = csvColumns csvTable
	
	rows csvTable = do
		lns <- lazyLines $ csvFileName csvTable
		return $ map (parseRow csvTable) lns
	
	count csvTable = Nothing -- Cannot pre-determine row count in CSV table
	
